package com.kl.controller;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kl.domain.*;
import com.kl.em.ConstantEnum;
import com.kl.em.Result;
import com.kl.entity.*;
import com.kl.feign.LineServcieFeign;
import com.kl.feign.LogisticsStoreControllerFeign;
import com.kl.feign.OrderServcieFeign;
import com.kl.service.ILineService;
import com.kl.vo.RouteVO;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author author
 * @since 2021-10-30
 */
@RestController
@RequestMapping("lineController")
@RefreshScope //nacos配置中心 开启自动刷新配置
public class LineController {

    @Autowired
    private ILineService lineService;
    @Autowired
    private LogisticsStoreControllerFeign logisticsStoreControllerFeign;
    @Autowired
    private LineServcieFeign lineServcieFeign;
    @Autowired
    private RestHighLevelClient client;

    @Autowired
    private OrderServcieFeign orderServcieFeign;

    //路线信息查询接口
    @ApiOperation(value = "路线信息查询接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "id",value = "线路id",required = true,paramType = "query")
    })
    @GetMapping// @ResponseBody  将后台的数据以json的格式返回前台
    public Result<LineDTO> selectById(@RequestParam("id") Long id) {// @RequestBody  将前端传入的json格式的数据绑定到实体类
        LineDTO lineDTO = new LineDTO();
        try {
            Line line = lineService.getById(id);
            BeanUtils.copyProperties(line, lineDTO);
        } catch (Exception e) {
            e.printStackTrace();
            return Result.build(ConstantEnum.ERROR);
        }
        return Result.build(ConstantEnum.SUCCESS).setResult(lineDTO);
    }

    //包含的路线信息查询接口
    @ApiOperation(value = "包含的当前城市的路线信息查询接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "address",value = "城市",required = true,paramType = "query")
    })
    @GetMapping("selectByAddress")// @ResponseBody  将后台的数据以json的格式返回前台
    public Result<List<LineDTO>> selectByCity(@RequestParam("address") String address) {
        //1.构建SearchRequest请求对象,指定索引库
        SearchRequest searchRequest = new SearchRequest("kunlunwuliu");
        //2.构建SearchSourceBuilder查询对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //3.构建QueryBuilder对象指定查询方式和条件
        BoolQueryBuilder builder =QueryBuilders.boolQuery();/**此处使用模糊匹配查询 类比数据库中 like*/
        QueryBuilder qb1= QueryBuilders.matchPhraseQuery("line_city", address);
        BoolQueryBuilder bqb1=QueryBuilders.boolQuery().must(qb1);
        builder.must(bqb1);
        //4.将QuertBuilder对象设置到SearchSourceBuilder中
        searchSourceBuilder.query(builder);
        searchSourceBuilder.size(1000);
        //5.将SearchSourceBuilder对象封装到请求对象SearchRequest中
        searchRequest.source(searchSourceBuilder);
        //6.调用方法执行数据通信
        SearchResponse search = null;
        try {
            search = client.search(searchRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //7.解析输出结果
        SearchHit[] hits = search.getHits().getHits();
        List<LineDTO> list = new ArrayList();
        for (SearchHit hit : hits) {
            String sourceAsString = hit.getSourceAsString();
            LineDTO lineDTO = JSONObject.parseObject(sourceAsString, LineDTO.class);
            list.add(lineDTO);
        }
        return Result.build(ConstantEnum.SUCCESS).setResult(list);
    }

    //路线信息查询接口
    @ApiOperation(value = "路线信息查询接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "statrAddress",value = "起点",required = true,paramType = "query"),
            @ApiImplicitParam(name = "endAddress",value = "终点",required = true,paramType = "query")
    })
    @GetMapping("selectByBoth")// @ResponseBody  将后台的数据以json的格式返回前台
    public Result<LineDTO> selectByBoth(@RequestParam("statrAddress") String statrAddress,@RequestParam("endAddress") String endAddress){// @RequestBody  将前端传入的json格式的数据绑定到实体类
        LineDTO lineDTO = new LineDTO();
        try {
            //调用接口，查询所有的站点
            Result<List<LogisticsStoreDTO>> listResult = logisticsStoreControllerFeign.selectLogisticsStoreAll();
            if(listResult.getCode().equals(1007)){
                System.out.println("站点熔断");
                return Result.build(ConstantEnum.FaillBack);
            }
            List<LogisticsStoreDTO> resultList = listResult.getResult();

            List<String> olist = new ArrayList<>();
            for (int i = 0; i < resultList.size(); i++) {
                //将所有站点放进 olist 集合中
                olist.add(resultList.get(i).getStoreAddr());
            }
            //获取起点城市的经纬度
            String start = getLngAndLag(statrAddress);
            //获取终点城市的经纬度
            String end = getLngAndLag(endAddress);
            //获取路线的长度以及所经过的城市//
            RouteVO<String> routeVO = getCity(start, end);
            List<String> route = routeVO.getRoute();
            QueryWrapper wrapper = new QueryWrapper();
            wrapper.like("statr_address",route.get(0));
            wrapper.like("end_address",route.get(route.size() - 1));
            List<Line> list = lineService.list(wrapper);
            if (list.size() == 0){
                return Result.build(ConstantEnum.NO_CITY);
            }
            Line line = list.get(0);
            BeanUtils.copyProperties(line,lineDTO);

             return Result.build(ConstantEnum.SUCCESS).setResult(lineDTO);

        }catch (Exception e){
            e.printStackTrace();
            return Result.build(ConstantEnum.ERROR).setResult("异常");
        }
    }

    //路线信息增加接口
    @ApiOperation(value = "路线信息增加接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "statrAddress",value = "起点",required = true,paramType = "query"),
            @ApiImplicitParam(name = "endAddress",value = "终点",required = true,paramType = "query")
    })
    @PostMapping// @ResponseBody  将后台的数据以json的格式返回前台
    public Result insertById(@RequestParam("statrAddress") String statrAddress,@RequestParam("endAddress") String endAddress){// @RequestBody  将前端传入的json格式的数据绑定到实体类
        try {
            //调用接口，查询所有的站点
            Result<List<LogisticsStoreDTO>> listResult = logisticsStoreControllerFeign.selectLogisticsStoreAll();
            if (listResult.getCode().equals(1007)){
                return Result.build(ConstantEnum.FaillBack).setResult("log服务熔断了");
            }
            List<LogisticsStoreDTO> resultList = listResult.getResult();
            List<String> olist = new ArrayList<>();
            for (int i = 0; i < resultList.size(); i++) {
                //将所有站点放进 olist 集合中
                olist.add(resultList.get(i).getStoreAddr());
            }
            LineDTO lineDTO = new LineDTO();

            //获取起点城市的经纬度
            String start = getLngAndLag(statrAddress);
            //获取终点城市的经纬度
            String end = getLngAndLag(endAddress);
            //获取路线的长度以及所经过的城市//
            RouteVO routeVO = getCity(start, end);
            //遍历routList
            List<String> list = new ArrayList<>();
            //路线
            //[北京市, 天津市, 沧州市市, 滨州市市, 淄博市市, 潍坊市市, 临沂市市, 日照市市, 连云港市市, 盐城市市, 南通市市, 苏州市市, 上海市]
            List<String> route = (List<String>) routeVO.getRoute();
            lineDTO.setStatrAddress(route.get(0));
            lineDTO.setEndAddress(route.get(route.size() - 1));
            //线路经过的那些城市
            for (int j = 0; j < route.size(); j++) {
                for (int i = 0; i < olist.size(); i++) {
                    //获取站点名称
                    String storeAddr = olist.get(i);
                    String s = route.get(j);
                    //判断站点名称中是否包含这个城市
                    if (storeAddr.contains(s)){
                        //判断字符串后面有没有包含市
                        if (!s.contains("市")){
                            s = route.get(j) + "市";
                        }
                        list.add(s);
                    }
                }
            }
            lineDTO.setLineCity(JSONObject.toJSONString(list));
            //线路长度
            long routLength = Long.parseLong(routeVO.getDistance());
            lineDTO.setLineLength(routLength/1000);
            //耗时，按照每小时100公里
            lineDTO.setLineTime(routLength/1000/100);
            //线路所经过的站点数量
            lineDTO.setSiteCount(list.size());
            String string = JSONObject.toJSONString(lineDTO);
            Line line = JSONObject.parseObject(string, Line.class);
            lineService.save(line);
            lineServcieFeign.insertByLLId(lineDTO.getId());
        }catch (Exception e){
            e.printStackTrace();
            return Result.build(ConstantEnum.ERROR);
        }
        return Result.build(ConstantEnum.SUCCESS);
    }

    //路线信息删除接口
    @ApiOperation(value = "路线信息删除接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "statrAddress",value = "起点",required = true,paramType = "query"),
            @ApiImplicitParam(name = "endAddress",value = "终点",required = true,paramType = "query")
    })
    @DeleteMapping// @ResponseBody  将后台的数据以json的格式返回前台
    public Result deleteByLineId(@RequestParam("id") String id){// @RequestBody  将前端传入的json格式的数据绑定到实体类
        try {
            lineService.removeById(id);
        }catch (Exception e){
            e.printStackTrace();
            return Result.build(ConstantEnum.ERROR);
        }
        return Result.build(ConstantEnum.SUCCESS);
    }

    //同城路线信息查询接口
    @ApiOperation(value = "同城路线信息查询接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "statrAddress",value = "起点",required = true,paramType = "query"),
            @ApiImplicitParam(name = "endAddress",value = "终点",required = true,paramType = "query")
    })
    @GetMapping("selectNameCity")
    public Result<RouteVO> selectNameCity(@RequestParam("statrAddress") String statrAddress,@RequestParam("endAddress") String endAddress){
        RouteVO city = null;
        try {
            String lngAndLag = getLngAndLag(statrAddress);
            String lngAndLag1 = getLngAndLag(endAddress);
            city = getCity(lngAndLag, lngAndLag1);
        } catch (Exception e) {
            e.printStackTrace();
            Result.build(ConstantEnum.ERROR);
        }
        return Result.build(ConstantEnum.SUCCESS).setResult(city);
    }

    //输入地址获取它的经纬度
    public static String getLngAndLag(String address) {
        String geturl = "http://restapi.amap.com/v3/geocode/geo?key=9ca045ff51765da1a75e72f38bf26831&address="+address;
        String location = "";
        try {
            URL url = new URL(geturl);    // 把字符串转换为URL请求地址
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 打开连接
            connection.connect();// 连接会话
            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {// 循环读取流
                sb.append(line);
            }
            br.close();// 关闭流
            connection.disconnect();// 断开连接
            JSONObject a = JSON.parseObject(sb.toString());
            //判断输入的位置点是否存在
            if(a.getJSONArray("geocodes").size()>0)
                location=a.getJSONArray("geocodes").getJSONObject(0).get("location").toString();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("失败!");
        }
        return location;
    }


    //获取线路所经过的城市 和 距离
    public static RouteVO getCity(String start,String end) {
        String geturl = "https://restapi.amap.com/v5/direction/driving?key=9ca045ff51765da1a75e72f38bf26831&origin=" + start + "&destination=" + end + "&show_fields=cities";
        RouteVO routeVO = new RouteVO();
        try {
            URL url = new URL(geturl);    // 把字符串转换为URL请求地址
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();// 打开连接
            connection.connect();// 连接会话
            // 获取输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {// 循环读取流
                sb.append(line);
            }
            br.close();// 关闭流
            connection.disconnect();// 断开连接
            //RouteVO routeVO = JSON.parseObject(sb.toString(), RouteVO.class);
            String route = JSONObject.parseObject(sb.toString()).getString("route");
            String paths = JSONObject.parseObject(route).getString("paths");
            List<Paths> pathsList = JSONArray.parseArray(paths, Paths.class);
            List<String> list = new ArrayList<>();
            List<Steps> stepsList = JSONArray.parseArray(pathsList.get(0).getSteps().toString(), Steps.class);
            for (int o = 0; o < stepsList.size(); o++) {
                List<Cities> cities = JSONArray.parseArray(stepsList.get(o).getCities().toString(), Cities.class);
                for (int j = 0; j < cities.size(); j++) {
                    String city = cities.get(j).getCity();
                    if (city.contains("城区")){
                        city = city.substring(0, city.length() - 2);
                    }
                    if (!list.contains(city)){
                        list.add(city);
                    }
                }
            }

            String distance = pathsList.get(0).getDistance();
            routeVO.setDistance(distance);
            routeVO.setRoute(list);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("失败!");
        }
        return routeVO;
    }

    @PostMapping("insertSiteName")
    @ApiOperation(value = "增加站点接口")
    @ApiImplicitParams({
            //name为方法中的参数名，value就是它的含义，required 是否必填
            @ApiImplicitParam(name = "siteName",value = "站点名称",required = true,paramType = "query"),
            @ApiImplicitParam(name = "resultList",value = "全部站点list集合",required = true,paramType = "body")
    })
    public Result selectCount(@RequestParam("siteName")String siteName,@RequestBody List<LogisticsStoreDTO> resultList) {
        //String str = "北京市市辖区东城区,天津市市辖区和平区,河北省石家庄市市辖区,山西省太原市市辖区,内蒙古自治区呼和浩特市市辖区,辽宁省沈阳市市辖区,吉林省长春市市辖区,黑龙江省哈尔滨市市辖区,上海市市辖区黄浦区,江苏省南京市市辖区,浙江省杭州市市辖区,安徽省合肥市市辖区,福建省福州市市辖区,江西省南昌市市辖区,山东省济南市市辖区,河南省郑州市市辖区,湖北省武汉市仙桃市,湖南省长沙市市辖区,广东省广州市市辖区,广西壮族自治区南宁市市辖区,海南省海口市五指山市,重庆市市辖区万州区,四川省成都市西昌市,贵州省贵阳市市辖区,云南省昆明市楚雄市,西藏自治区拉萨市林芝县,陕西省西安市市辖区,甘肃省兰州市市辖区,青海省西宁市市辖区,宁夏回族自治区银川市市辖区,新疆维吾尔自治区乌鲁木齐市石河子市";
        try {
            System.out.println("进入line");
            //调用接口，查询所有的站点
//            Result<List<LogisticsStoreDTO>> resultList = logisticsStoreControllerFeign.selectLogisticsStoreAll();
            String str = "";
         //   List<LogisticsStoreDTO> resultList = listResult.getResult();
            for (int i = 0; i < resultList.size(); i++) {
                str += resultList.get(i).getStoreAddr() + ",";
            }
            String[] split = str.split(",");
            List<String> list = new ArrayList<>();
            for (int i = 0; i < split.length; i++) {
                list.add(split[i]);
            }
            System.out.println(list);
            for (int i = 0; i < list.size() - 1; i++) {
                insertById(list.get(i),siteName);
            }
        }catch (Exception e){
            e.printStackTrace();
            return Result.build(ConstantEnum.ERROR);
        }
        return Result.build(ConstantEnum.SUCCESS);

    }

    public static void main(String[] args) throws UnsupportedEncodingException {
                                                                                                          //117.150738,39.138203
        String str = getLngAndLag("天津市市辖区南开区");//  116.416357,39.928353    天津市市辖区和平区 -> 123.395680,41.789450
        //RouteVO routeVO = getCity("116.416357,39.928353", "123.395680,41.789450");
        System.out.println(str);
    }

    //循环添加当前所拥有的所有站点   保证所有站点相连
    public static void test() throws UnsupportedEncodingException {
        String str = "北京市市辖区东城区,天津市市辖区南开区,河北省石家庄市市辖区,山西省太原市市辖区,内蒙古自治区呼和浩特市市辖区,辽宁省沈阳市市辖区,吉林省长春市市辖区,黑龙江省哈尔滨市市辖区,上海市,江苏省南京市市辖区,浙江省杭州市市辖区,安徽省合肥市市辖区,福建省福州市市辖区,江西省南昌市市辖区,山东省济南市市辖区,河南省郑州市市辖区,湖北省武汉市仙桃市,湖南省长沙市市辖区,广东省广州市市辖区,广西壮族自治区南宁市市辖区,海南省海口市,重庆市市辖区万州区,四川省成都市西昌市,贵州省贵阳市市辖区,云南省昆明市楚雄市,西藏自治区拉萨市林芝县,陕西省西安市市辖区,甘肃省兰州市市辖区,青海省西宁市市辖区,宁夏回族自治区银川市市辖区,新疆维吾尔自治区乌鲁木齐市石河子市";
        String[] split = str.split(",");
        List<String> olist = new ArrayList<>();
        List<String> plist = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            olist.add(split[i]);
            plist.add(split[i]);
        }
        System.out.println(olist);
        LineDTO lineDTO = new LineDTO();
        for (int i = 0; i < olist.size(); i++) {
            for (int j = 0; j < plist.size(); j++) {
                if (i != j){
                    System.out.println(i + " =======" + j);
                    //获取起点经纬度
                    String star = getLngAndLag(olist.get(i));
                    //获取终点经纬度
                    String end = getLngAndLag(plist.get(j));
                    //获取路线的城市
                    RouteVO city = getCity(star, end);
                    //获取路线经过的城市
                    List<String> route = (List<String>) city.getRoute();
                    System.out.println(route);
                    List<String> list = new ArrayList<>();
                    for (int o = 0; o < route.size(); o++) {
                        //获取每个城市的名称
                        String s = route.get(o);
                        for (int p = 0; p < olist.size(); p++) {
                            //获取每个站点名称
                            String storeAddr = olist.get(p);
                            //判断站点名称中是否包含这个城市
                            if (storeAddr.contains(s)){
                                //判断字符串后面有没有包含市
                                list.add(s);
                            }
                        }
                    }
                    System.out.println(list);
                    lineDTO.setStatrAddress(list.get(0));
                    lineDTO.setEndAddress(list.get(list.size()-1));
                    lineDTO.setLineCity(JSONObject.toJSONString(list));
                    //线路长度
                    long routLength = Long.parseLong(city.getDistance());
                    lineDTO.setLineLength(routLength);
                    //耗时，按照每小时100公里
                    lineDTO.setLineTime(routLength/100);
                    //线路所经过的站点数量
                    lineDTO.setSiteCount(list.size());
                    String string = JSONObject.toJSONString(lineDTO);
                    Line line = JSONObject.parseObject(string, Line.class);
                    System.out.println(line);
                    //lineService.save(line);
                }
            }
        }
    }
    /*@ApiOperation(value = "asd询接口")
    @GetMapping("asd")
    public Result asd(){
        Result<List<WaybillDTO>> result = orderServcieFeign.likeWaybill("1");
        System.out.println(result.getMessage());
        return result;
    }*/
}
